package perso.marcr.lst.service.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Service;

import perso.marcr.lst.cron.LaunchTaskCron;
import perso.marcr.lst.model.TaskList;
import perso.marcr.lst.model.Status;
import perso.marcr.lst.service.CronService;

@Service
public class CronServiceImpl implements CronService{


	private static final String DEFAULT_TRIGGER_GROUP = "group";

	private static Scheduler scheduler = null;

	public CronServiceImpl() throws SchedulerException
	{
		scheduler = new StdSchedulerFactory().getScheduler();
		scheduler.start();
	}

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.CronService#getCurrentlyExecutingJobs()
	 */
	public List<TaskList> getCurrentlyExecutingJobs() throws SchedulerException {

		List<JobExecutionContext> jobsList=scheduler.getCurrentlyExecutingJobs();

		List<TaskList> listResult = new ArrayList<TaskList>();
		for(int i=0; i<jobsList.size(); i++)
		{
			JobExecutionContext jec = jobsList.get(i);
			TaskList el = new TaskList();
			el.setJobName(jec.getJobDetail().getJobDataMap().getString("jobName"));
			el.setTaskId(jec.getJobDetail().getJobDataMap().getString("taskId"));
			el.setStatus(Status.RUNNING);
			listResult.add(el);
		}

		return listResult;
	}

	public List<TaskList> getPendingJobs() throws SchedulerException {
		List<TaskList> listResult = new ArrayList<TaskList>();
		//loop all group
		for (String groupName : scheduler.getJobGroupNames()) {

			//loop all jobs by groupname
			for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {

				String jobName = jobKey.getName();
				//String jobGroup = jobKey.getGroup();

				//get job's trigger
				List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
				Date nextFireTime = triggers.get(0).getNextFireTime();
				String szTaskId = perso.marcr.util.Date.format(nextFireTime);

				if(nextFireTime!=null)
				{
					TaskList el = new TaskList();
					el.setJobName(jobName);
					el.setTaskId(szTaskId);
					el.setStatus(Status.PENDING);
					listResult.add(el);
				}
			}
		}
		return listResult;
	}

	/* (non-Javadoc)
	 * @see perso.marcr.lst.service.CronService#fireNow(java.lang.String)
	 */
	public void fireNow(String szJobName) throws SchedulerException {		
		String triggerName=szJobName;
		String triggerGroup=DEFAULT_TRIGGER_GROUP;

		JobKey jobKey = new JobKey(triggerName, triggerGroup);
		scheduler.triggerJob(jobKey);
	}

	public void updateCron(String jobName, String cronExpression) throws SchedulerException, ParseException {
		removeFromCron(jobName);
		addCron(jobName,cronExpression);
	}

	public void removeFromCron(String jobName) throws SchedulerException {
		String triggerName=jobName;
		String triggerGroup=DEFAULT_TRIGGER_GROUP;

		TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroup);
		CronTriggerImpl trigger = (CronTriggerImpl) scheduler.getTrigger(triggerKey);

		if(trigger != null)
		{ // job found, unschedule it:			
			scheduler.unscheduleJob(triggerKey);
		}

	}

	/**
	 * @param szJobName
	 * @param cronExpression
	 * @throws ParseException
	 * @throws SchedulerException
	 */
	private void addCron(String szJobName, String cronExpression) throws ParseException, SchedulerException {

		if(CronExpression.isValidExpression(cronExpression)) {
			/// Data map:
			JobDataMap jdm = new JobDataMap();
			jdm.put("jobName", szJobName);

			// Build job:
			JobDetail job = JobBuilder.newJob(LaunchTaskCron.class).setJobData(jdm)
					.withIdentity(szJobName, DEFAULT_TRIGGER_GROUP).build();			


			// Build Trigger
			Trigger trigger = TriggerBuilder
					.newTrigger()
					.withIdentity(szJobName, DEFAULT_TRIGGER_GROUP)
					.withSchedule(
							CronScheduleBuilder.cronSchedule(cronExpression))
							.build();


			// Schedule		
			scheduler.scheduleJob(job, trigger);
		}
	}


}
